﻿using MathNet.Numerics;
using OpenCvSharp;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reactive;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using 摸鱼;

public class DXGIFastCapture : IDisposable
{
    private Factory1 factory;
    private Adapter1 adapter;
    private Output output;
    private Output1 output1;
    private OutputDuplication duplication;
    private SharpDX.Direct3D11.Device device;
    private Texture2D stagingTexture;
    private PixelLevelTransparentForm form;

    private int width;
    private int height;
    private unsafe byte* matDataPtr;
    private Mat[] frameBuffers = new Mat[2]; // 双缓冲
    private Mat newFrame = new();
    private Stopwatch newFrameTime = new();
    private int currentBufferIndex = 0;
    private object captureLock = new();

    public DXGIFastCapture(MainWindow minForm, int outputIndex = 0)
    {
        Initialize(minForm, outputIndex);
    }

    private void Initialize(MainWindow minForm, int outputIndex)
    {
        try
        {
            // 1. 创建 DXGI 工厂
            factory = new Factory1();

            // 2. 获取适配器（显卡）
            adapter = factory.GetAdapter1(0);

            // 3. 创建 Direct3D 11 设备
            device = new SharpDX.Direct3D11.Device(adapter);

            // 4. 获取输出（显示器）
            output = adapter.GetOutput(outputIndex);
            output1 = output.QueryInterface<Output1>();

            // 5. 获取显示器信息
            var outputDesc = output.Description;
            width = outputDesc.DesktopBounds.Right - outputDesc.DesktopBounds.Left;
            height = outputDesc.DesktopBounds.Bottom - outputDesc.DesktopBounds.Top;

            // 6. 创建桌面复制接口
            duplication = output1.DuplicateOutput(device);

            // 7. 预分配资源
            InitializeResources();

            // 8. 创建透明窗体以确保 DXGI 能检测到变化
            Thread thread = new Thread(() =>
            {
                form = new(minForm);
                form.Show();
                System.Windows.Forms.Application.Run(new ApplicationContext());
            });
            thread.IsBackground = true;
            thread.Start();

            // 9. 启动计时器
            newFrameTime.Start();

            Console.WriteLine($"DXGI 截图初始化完成: {width}x{height}");
        }
        catch (Exception ex)
        {
            throw new Exception($"DXGI 初始化失败: {ex.Message}");
        }
    }

    private void InitializeResources()
    {
        // 创建 staging texture（CPU 可读）
        var textureDesc = new Texture2DDescription
        {
            Width = width,
            Height = height,
            MipLevels = 1,
            ArraySize = 1,
            Format = Format.B8G8R8A8_UNorm,
            SampleDescription = new SampleDescription(1, 0),
            Usage = ResourceUsage.Staging,
            BindFlags = BindFlags.None,
            CpuAccessFlags = CpuAccessFlags.Read,
            OptionFlags = ResourceOptionFlags.None
        };

        stagingTexture = new Texture2D(device, textureDesc);

        unsafe
        {
            // 创建双缓冲
            frameBuffers[0] = new Mat(height, width, MatType.CV_8UC4);
            frameBuffers[1] = new Mat(height, width, MatType.CV_8UC4);
            matDataPtr = frameBuffers[0].DataPointer;
        }
    }

    public unsafe Mat CaptureFrame()
    {
        if (Monitor.TryEnter(captureLock))
        {
            try
            {
                SharpDX.DXGI.Resource resource;
                OutputDuplicateFrameInformation frameInfo;

                // 使用最小超时
                if (duplication.TryAcquireNextFrame(0, out frameInfo, out resource) != SharpDX.Result.Ok)
                    return new Mat(newFrame, new OpenCvSharp.Rect(new OpenCvSharp.Point(0, 0), newFrame.Size())); // 说明屏幕无变化, 直接返回

                using (var texture = resource.QueryInterface<Texture2D>())
                using (resource)
                {
                    // 异步复制资源
                    device.ImmediateContext.CopyResource(texture, stagingTexture);

                    var dataBox = device.ImmediateContext.MapSubresource(
                        stagingTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None);

                    byte* srcPtr = (byte*)dataBox.DataPointer.ToPointer();
                    int sourceStride = dataBox.RowPitch;
                    int destStride = width * 4; // CV_8UC3 的步长
                    if (sourceStride == destStride)
                    {
                        // 步长相同，可以直接复制
                        System.Buffer.MemoryCopy(srcPtr, matDataPtr, width * height * 4, width * height * 4);
                        try { duplication.ReleaseFrame(); } catch { } //尽量减少释放当前帧和获取下一帧之间的间隔时间
                        // 返回当前缓冲区的引用
                        newFrame = frameBuffers[currentBufferIndex];
                        newFrameTime.Restart();
                        // 切换到下一个缓冲区
                        currentBufferIndex = currentBufferIndex == 0 ? 1 : 0;
                        matDataPtr = frameBuffers[currentBufferIndex].DataPointer;
                        return new Mat(newFrame, new OpenCvSharp.Rect(new OpenCvSharp.Point(0, 0), newFrame.Size()));
                    }
                    return null; // 步长不同，暂不处理
                }
            }
            catch (SharpDXException ex) when (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
            {
                return null;
            }
            finally
            {
                Monitor.Exit(captureLock);
                device.ImmediateContext.UnmapSubresource(stagingTexture, 0);
            }
        }
        else
        {
            while (newFrameTime.ElapsedMilliseconds > 33)
                MoyuDelay.Star(1);
            return new Mat(newFrame, new OpenCvSharp.Rect(new OpenCvSharp.Point(0, 0), newFrame.Size()));
        }
    }
    public void Dispose()
    {
        form.Dispose();
        frameBuffers.Aggregate((a, b) => { a.Dispose(); b.Dispose(); return b; });
        stagingTexture?.Dispose();
        duplication?.Dispose();
        output1?.Dispose();
        output?.Dispose();
        device?.Dispose();
        adapter?.Dispose();
        factory?.Dispose();
    }

    public class PixelLevelTransparentForm : Form
    {
        private const int GWL_EXSTYLE = -20;
        private const int WS_EX_LAYERED = 0x80000;
        private const int WS_EX_NOACTIVATE = 0x08000000;
        private const int WS_EX_TOPMOST = 0x00000008;
        private const int WS_EX_TRANSPARENT = 0x00000020; // 鼠标穿透关键样式
        private const int LWA_ALPHA = 0x2;

        private Random random = new Random();
        private Bitmap bufferBitmap;
        private Graphics bufferGraphics;

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll")]
        static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);

        [DllImport("user32.dll")]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        private const uint SWP_NOSIZE = 0x0001;
        private const uint SWP_NOMOVE = 0x0002;
        private const uint SWP_NOACTIVATE = 0x0010;
        private readonly MainWindow mainForm;

        public PixelLevelTransparentForm(MainWindow mainForm)
        {
            this.mainForm = mainForm;
            mainForm.Closing += (s, e) => this.Invoke(new Action(() => this.Close()));
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.Size = new System.Drawing.Size(100, 100);
            this.StartPosition = FormStartPosition.Manual;
            this.Location = new System.Drawing.Point(100, 100);
            this.FormBorderStyle = FormBorderStyle.None;
            this.ShowInTaskbar = false;

            // 在窗体显示前设置扩展样式
            this.Load += (s, e) => SetWindowStyles();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            SetWindowStyles();
            InitializeBuffersAndTimer();
        }

        private void SetWindowStyles()
        {
            // 获取当前扩展样式
            int style = GetWindowLong(this.Handle, GWL_EXSTYLE);

            // 设置分层、不激活、置顶、透明（鼠标穿透）样式
            style |= WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST | WS_EX_TRANSPARENT;
            SetWindowLong(this.Handle, GWL_EXSTYLE, style);

            // 设置透明度
            SetLayeredWindowAttributes(this.Handle, 0, 1, LWA_ALPHA);

            // 使用SetWindowPos确保置顶但不激活
            SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0,
                        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
        }

        private void InitializeBuffersAndTimer()
        {
            // 创建双缓冲
            bufferBitmap = new Bitmap(this.Width, this.Height);
            bufferGraphics = Graphics.FromImage(bufferBitmap);
            TriggerPixelChanges();
        }

        private void TriggerPixelChanges()
        {
            // 随机改变几个像素的颜色（几乎不可见但DXGI能检测）
            Thread thread = new Thread(() =>
            {
                while (!this.IsDisposed)
                {
                    for (int i = 0; i < 3; i++) // 减少数量提高性能
                    {
                        int x = random.Next(this.Width);
                        int y = random.Next(this.Height);

                        // 使用几乎透明的颜色
                        using (var brush = new SolidBrush(Color.FromArgb(1, random.Next(256), random.Next(256), random.Next(256))))
                        {
                            bufferGraphics.FillRectangle(brush, x, y, 1, 1);
                        }
                    }
                    // 触发重绘, 等待间隔等于屏幕刷新间隔
                    this.Invoke(Refresh);
                }
            });
            thread.IsBackground = true;
            thread.Start();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            // 将缓冲区绘制到窗体
            lock (bufferBitmap)
            {
                e.Graphics.DrawImage(bufferBitmap, 0, 0);
            }
        }

        // 重写这些方法防止窗体获得焦点
        protected override bool ShowWithoutActivation => true;

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= (int)(WS_EX_NOACTIVATE | WS_EX_TOPMOST | WS_EX_TRANSPARENT);
                return cp;
            }
        }

        // 添加额外的鼠标消息处理确保穿透
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_NCHITTEST = 0x0084;

            if (m.Msg == WM_NCHITTEST)
            {
                // 直接返回透明区域，让鼠标穿透
                m.Result = (IntPtr)(-1); // HTTRANSPARENT
                return;
            }

            base.WndProc(ref m);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                bufferGraphics?.Dispose();
                bufferBitmap?.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}